from copy import copy

import native

from util import *

def isTreeReducible(tree):
  lex, dyn, code=tree

  ftype=code[0]

  if ftype=='literal' or ftype=='symdef' or ftype=='block':
    return False
  elif ftype=='symref':
    return True
  elif ftype=='func':
    fname=code[1][0]
    fargs=code[1][1]

    for arg in fargs:
      if isTreeReducible(arg):
        return True
    return False
  elif ftype=='native':
    fname=code[1][0]
    fargs=code[1][1]

    if checkResolved(tree):
      return True
    else:
      for arg in fargs:
        if isTreeReducible(arg):
          return True
  else:
    print('Unsupported reduction type!: '+str(tree))

  return False

def isBranchReducible(branch):
  return checkNative(branch) and checkResolved(branch)

def reduceTree(system, userlib, tree):
  lex, dyn, code=tree

  ftype=code[0]

  if ftype=='literal' or ftype=='symdef' or ftype=='block':
    return tree
  elif ftype=='symref':
    return reduceBranch(system, userlib, tree)
  elif ftype=='native':
    if checkLiteral(tree) or checkResolved(tree):
      return reduceBranch(system, userlib, tree)
    else:
      ftype=code[0]
      fname=code[1][0]
      fargs=code[1][1]

      args=copy(fargs)
      for x in range(len(args)):
        args[x]=reduceTree(system, userlib, args[x])
        tree=(lex, dyn, [ftype, [fname, args]])
      return tree
  elif ftype=='func':
    ftype=code[0]
    fname=code[1][0]
    fargs=code[1][1]

    args=copy(fargs)
    for x in range(len(args)):
      args[x]=reduceTree(system, userlib, args[x])
      tree=(lex, dyn, [ftype, [fname, args]])
    return tree
  else:
    print('Unsupported reduction: '+str(tree))

  return tree

def reduceBranch(system, userlib, branch):
  lex=branch[0]
  dyn=branch[1]
  code=branch[2]

  ftype=code[0]

  if ftype=='symref':
    varName=code[1]
    value=lookup(system, userlib, lex, dyn, varName)
    if type(value)==dict:
      value=['block', value]
    return tuplifyTree(lex, dyn, value)
  elif ftype=='native':
    fname=code[1][0]
    fargs=code[1][1]

    f=getattr(native, fname)
    nativeArgs=[lex, dyn]+stripLiterals(fargs)
    result=f(*nativeArgs)
    if result!=None:
      if type(result)==str or type(result)==int or type(result)==bool or type(result)==float:
        result=(lex, dyn, ['literal', result])
      elif type(result)!=tuple:
        result=(lex, dyn, result)
      else:
        return result
    return result
  else:
    print('Unsupported reduction: '+str(branch))
